﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Xml.Serialization;
using System.IO;
using RecipeManager.Layout;
using System.Diagnostics;
namespace RecipeManager
{
    [Serializable]
    public class Recipe : INotifyPropertyChanged, ICloneable
    {
        #region UniqueRecipeID

        private int _uniqueRecipeID = 0;

        // a unique ID, folderNr
        [XmlIgnore]
        public int UniqueRecipeID
        {
            get { return _uniqueRecipeID; }
            set { OnPropertyChanged(_uniqueRecipeID, _uniqueRecipeID = value, "UniqueRecipeID"); }
        }

        #endregion

        #region Name

        private string _name = "";

        // Title e.g.: Cupcake
        [XmlAttribute]
        public string Name
        {
            get { return _name; }
            set { OnPropertyChanged(_name, _name = value, "Name"); }
        }

        #endregion

        #region PictureName

        public const string RecipeDefaultPictureName = "Recipe.jpg";
        private string _pictureName = RecipeDefaultPictureName;

        [DefaultValue(RecipeDefaultPictureName)]
        [XmlAttribute]
        public string PictureName
        {
            get { return _pictureName; }
            set { OnPropertyChanged(_pictureName, _pictureName = value, "PictureName"); }
        }

        #endregion

        #region Count

        // e.g.: recipe is good for 10 cookies
        private string _count = "1";

        [DefaultValue("1")]
        [XmlAttribute]
        public string Count
        {
            get { return _count; }
            set { OnPropertyChanged(_count, _count = value, "Count"); }
        }

        #endregion

        #region Time for creation

        // e.g.: takes 5-10 minutes depending on the quality of the floor

        private int _minTimeInMinutes = 0;
        [DefaultValue(0)]
        [XmlAttribute]
        public int MinTimeInMinutes
        {
            get { return _minTimeInMinutes; }
            set { OnPropertyChanged(_minTimeInMinutes, _minTimeInMinutes = value, "MinTimeInMinutes"); }
        }

        // enter zero to hide it
        private int _maxTimeInMinutes = 0;
        [DefaultValue(0)]
        [XmlAttribute]
        public int MaxTimeInMinutes
        {
            get { return _maxTimeInMinutes; }
            set { OnPropertyChanged(_maxTimeInMinutes, _maxTimeInMinutes = value, "MaxTimeInMinutes"); }
        }

        private string _timeDescription = "";
        [DefaultValue("")]
        [XmlAttribute]
        public string TimeDescription
        {
            get { return _timeDescription; }
            set { OnPropertyChanged(_timeDescription, _timeDescription = value, "TimeDescription"); }
        }

        #endregion

        #region Ingredients

        private List<IngredientUsage> _ingredientList = new List<IngredientUsage>();
        public List<IngredientUsage> IngredientList
        {
            get { return _ingredientList; }
        }

        public string IngredientListValues
        {
            get
            {
                string Result = "";
                if (IngredientList != null)
                {
                    string delim = "";
                    foreach (var ingredient in IngredientList)
                    {
                        Result += delim + ingredient.IngredientName;
                        delim = ", ";
                    }
                }
                return Result;
            }
        }
        private string _ingredientPictureName = "";
        [DefaultValue("")]
        [XmlAttribute]
        public string IngredientPictureName
        {
            get { return _ingredientPictureName; }
            set { OnPropertyChanged(_ingredientPictureName, _ingredientPictureName = value, "IngredientPictureName"); }
        }

        #endregion

        #region Preparation

        private List<RecipePreparation> _preparation = new List<RecipePreparation>();
        public List<RecipePreparation> Preparation
        {
            get { return _preparation; }
        }

        private string _preparationPictureName = "";
        [DefaultValue("")]
        [XmlAttribute]
        public string PreparationPictureName
        {
            get { return _preparationPictureName; }
            set { OnPropertyChanged(_preparationPictureName, _preparationPictureName = value, "PreparationPictureName"); }
        }

        #endregion

        #region Hint

        private string _hint = "";
        [DefaultValue("")]
        public string Hint
        {
            get { return _hint; }
            set { OnPropertyChanged(_hint, _hint = value, "Hint"); }
        }

        private string _hintPictureName = "";
        [DefaultValue("")]
        [XmlAttribute]
        public string HintPictureName
        {
            get { return _hintPictureName; }
            set { OnPropertyChanged(_hintPictureName, _hintPictureName = value, "HintPictureName"); }
        }

        #endregion

        #region Category

        private List<Category> _categories = new List<Category>();

        public List<Category> Categories
        {
            get { return _categories; }
        }

        public string CategoryValues
        {
            get
            {
                string Result = "";
                string delim = "";

                if (Categories != null)
                {
                    foreach (var category in Categories)
                    {
                        Result += (delim + category.Name);
                        delim = ", ";
                    }
                }

                return Result;
            }
        }
        #endregion

        #region AdditionalInfo

        private string _additionalInfo = "";
        [DefaultValue("")]
        public string AdditionalInfo
        {
            get { return _additionalInfo; }
            set { OnPropertyChanged(_additionalInfo, _additionalInfo = value, "AdditionalInfo"); }
        }

        #endregion

        #region DataPicture

        private string _dataPicture = "";
        [DefaultValue("")]
        public string DataPicture
        {
            get { return _dataPicture; }
            set { OnPropertyChanged(_dataPicture, _dataPicture = value, "DataPicture"); }
        }

        #endregion

        #region DateOfCreation
        private DateTime _dateOfCreation = DateTime.Now;
        [XmlAttribute]
        public DateTime DateOfCreation
        {
            get { return _dateOfCreation; }
            set { OnPropertyChanged(_dateOfCreation, _dateOfCreation = value, "DateOfCreation"); }
        }

        #endregion

        #region DateOfLastEdited

        private DateTime _dateOfLastEdited = DateTime.Now;
        [XmlAttribute]
        public DateTime DateOfLastEdited
        {
            get { return _dateOfLastEdited; }
            set { OnPropertyChanged(_dateOfLastEdited, _dateOfLastEdited = value, "DateOfLastEdited"); }
        }

        private void SetUpdated()
        {
            _dateOfLastEdited = DateTime.Now;
        }

        #endregion

        #region INotifyPropertyChanged Member

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(object val1, object val2, string propName = "")
        {
            if (!(val1 == null && val2 == null))
            {
                if (val1 == null || !val1.Equals(val2))
                {
                    if (PropertyChanged != null)
                    {
                        PropertyChanged(this, new PropertyChangedEventArgs(propName));
                    }
                    SetUpdated();
                }
            }
        }

        #endregion

        #region ICloneable Member

        public object Clone()
        {
            Recipe result = new Recipe();

            result.UniqueRecipeID = _uniqueRecipeID;
            result.Name = _name;
            result.PictureName = _pictureName;
            result.Count = _count;

            result.MinTimeInMinutes = _minTimeInMinutes;
            result.MaxTimeInMinutes = _maxTimeInMinutes;
            result.TimeDescription = _timeDescription;

            _ingredientList.ForEach(x => result.IngredientList.Add(x.Clone() as IngredientUsage));
            result.IngredientPictureName = _ingredientPictureName;

            _preparation.ForEach(x => result.Preparation.Add(x.Clone() as RecipePreparation));
            result.PreparationPictureName = _preparationPictureName;

            result.Hint = _hint;
            result.HintPictureName = _hintPictureName;

            _categories.ForEach(x => result.Categories.Add(x.Clone() as Category));

            result.DataPicture = _dataPicture;
            result.AdditionalInfo = _additionalInfo;

            result.DateOfCreation = _dateOfCreation;
            result.DateOfLastEdited = _dateOfLastEdited;

            return result;
        }

        #endregion

        #region Save

        public static string RepositoryPath
        {
            get
            {
                string content = "./data/";

                if (!Directory.Exists(content))
                {
                    Directory.CreateDirectory(content);
                }

                return content;
            }
        }
        public static string MainRecipeFileName = "recipe.xml";

        public static string GenerateFileName(int id, string prefix = "")
        {
            return string.Format("{1}{0:0000000000}/", id, prefix);
        }

        public static string GenerateFileNameByString(string id, string prefix = "")
        {
            return string.Format("{1}{0}/", id, prefix);
        }

        public string SavePath
        {
            get
            {
                return RepositoryPath + GenerateFileName(UniqueRecipeID);
            }
        }

        public void Save()
        {

            if (!Directory.Exists(SavePath))
            {
                Directory.CreateDirectory(SavePath);
            }

            using (FileStream stream = new FileStream(SavePath + MainRecipeFileName,
                FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite))
            {
                XmlSerializer serializer = new XmlSerializer(typeof(Recipe));
                serializer.Serialize(stream, this);
            }
        }

        #endregion

        #region Delete

        public void Delete()
        {
            string delpath = RepositoryPath + GenerateFileName(UniqueRecipeID, string.Format("d {0} {1} ",
                DateTime.Now.ToShortDateString(), DateTime.Now.ToLongTimeString().Replace(':', '.')));

            if (!Directory.Exists(RepositoryPath))
            {
                return;
            }

            if (Directory.Exists(SavePath))
            {
                Directory.Move(SavePath, delpath);
            }

        }

        #endregion

        #region Load

        public static Recipe Load(int uniqueRecipeID)
        {
            string fileName = RepositoryPath + GenerateFileName(uniqueRecipeID) + MainRecipeFileName;
            if (File.Exists(fileName))
            {
                using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    XmlSerializer serializer = new XmlSerializer(typeof(Recipe));

                    Recipe recipe = serializer.Deserialize(stream) as Recipe;
                    recipe.UniqueRecipeID = uniqueRecipeID;
                    return recipe;
                }
            }

            return null;
        }

        public static List<int> GetRecipiesInRepository()
        {
            List<int> recipies = new List<int>();
            int tmp;

            recipies.AddRange(
                Directory.GetDirectories(RepositoryPath).ToList().
                    Where(x => Path.GetFileName(x).Length >= 10 && int.TryParse(Path.GetFileName(x), out tmp)).ToList().
                        ConvertAll<int>(x => int.Parse(Path.GetFileName(x))));

            return recipies;
        }

        #endregion

        private RecipeLayoutType _layoutType = RecipeLayoutType.HTML1;

        [DefaultValue(RecipeLayoutType.HTML1)]
        public RecipeLayoutType LayoutType
        {
            get
            {
                return _layoutType;
            }
            set
            {
                _layoutType = value;
            }
        }

        [XmlIgnore]
        public string HTMLReportPath
        {
            get
            {

                string path = SavePath + DefaultReportFileName;
                GenerateHTMLReport(path);

                return path;

            }
        }

        public const string DefaultReportFileName = "report.html";

        public string GenerateHTMLReportBody()
        {
            return GenerateHTMLReportBody(this);
        }

        public static string GenerateHTMLReportBody(Recipe recipe)
        {
            switch (recipe.LayoutType)
            {
                case RecipeLayoutType.HTML1:
                    return LayoutGeneratorHTML1.GenerateHTMLBody(recipe);
            }

            return "";
        }

        public void GenerateHTMLReport(string fileName)
        {
            string content = "";
            switch (_layoutType)
            {
                case RecipeLayoutType.HTML1:
                    content = LayoutGeneratorHTML1.GenerateHTMLFile(this);
                    break;
            }
            File.WriteAllText(fileName, content);
        }

        public void OpenFolder()
        {
            Process.Start(Path.GetFullPath(SavePath));
        }
    }
}
